import static akka.actor.Actors.actorOf;

import java.util.ArrayList;
import java.util.List;

import akka.actor.ActorRef;
import akka.actor.UntypedActor;
import akka.actor.UntypedActorFactory;

/**
 * The main class that drives the Airport check in model.
 * 
 * @author Peter-John Rowe
 * @author Michael Allioto
 * @author Evan
 *
 */
public class Main {
	
	private static final int NUM_LINES = 2;
	private static final int NUM_PASSENGERS = 10;
	
	
	/**
	 * Main method.
	 * 
	 * @param args
	 */
	public static void main(String args[]) {
		
		Main driver = new Main();
		
		ActorRef jail = actorOf(driver.new JailFactory(NUM_LINES)).start();
		
		List<ActorRef> queueList = new ArrayList<ActorRef>(NUM_LINES);
		for (int i = 1; i <= NUM_LINES; i++) {
			ActorRef security = actorOf(driver.new SecurityFactory(i, jail));
			ActorRef bodyScan = actorOf(driver.new BodyScannerFactory(i, security));
			ActorRef bagScan = actorOf(driver.new BaggageScannerFactory(i, security));
			ActorRef queue = actorOf(driver.new QueueFactory(i, bagScan));
			((Queue) queue.actor()).setBodyScan(bodyScan);
			((BodyScanner) bodyScan.actor()).setQueue(queue);
			security.start();
			bodyScan.start();
			bagScan.start();
			queue.start();
			queueList.add(queue);
		}
		ActorRef documentCheck = actorOf(driver.new DocumentCheckFactory(queueList)).start();
		
		// Begin sending passengers
		for (int p = 1; p <= NUM_PASSENGERS; p++) {
			documentCheck.tell(new Passenger(p));
		}
		documentCheck.tell(new Pill());
	}


	class JailFactory implements UntypedActorFactory{
		private int numLines;
		public JailFactory(int numLines) { this.numLines = numLines; }

		@Override
		public UntypedActor create() { return new Jail(numLines); }
	}
	
	class SecurityFactory implements UntypedActorFactory{
		private int lineNumber;
		private ActorRef jail;
		public SecurityFactory(int lineNumber, ActorRef jail) { 
			this.lineNumber = lineNumber;
			this.jail = jail;
		}

		@Override
		public UntypedActor create() { return new SecurityStation(lineNumber, jail); }
	}
	
	class BaggageScannerFactory implements UntypedActorFactory{
		private int lineNumber;
		private ActorRef security;
		public BaggageScannerFactory(int lineNumber, ActorRef security) { 
			this.lineNumber = lineNumber;
			this.security = security;
		}

		@Override
		public UntypedActor create() { return new BaggageScanner(lineNumber, security); }
	}
	
	class BodyScannerFactory implements UntypedActorFactory{
		private int lineNumber;
		private ActorRef security;
		public BodyScannerFactory(int lineNumber, ActorRef security) { 
			this.lineNumber = lineNumber;
			this.security = security;
		}

		@Override
		public UntypedActor create() { return new BodyScanner(lineNumber, security); }
	}
	
	class QueueFactory implements UntypedActorFactory{
		private int lineNumber;
		//private ActorRef bodyScan;
		private ActorRef bagScan;
		public QueueFactory(int lineNumber, /*ActorRef bodyScan, */ActorRef bagScan) { 
			this.lineNumber = lineNumber;
			//this.bodyScan = bodyScan;
			this.bagScan = bagScan;
		}

		@Override
		public UntypedActor create() { return new Queue(lineNumber, bagScan); }
	}
	
	class DocumentCheckFactory implements UntypedActorFactory{
		private List<ActorRef> queues;
		public DocumentCheckFactory(List<ActorRef> queues) { this.queues = queues; }

		@Override
		public UntypedActor create() { return new DocumentCheck(queues); }
	}
}
